#include "XXtitleBar.h"
#include "ui_XXtitleBar.h"
#include <QPixmap>
#include <QIcon>
#include <QEvent>

#include <QResizeEvent>
#ifdef Q_OS_WIN
#pragma comment(lib, "user32.lib")
#include <qt_windows.h>
#endif
#include <QStyle>

#include <QWindow>
#include <QSizePolicy>

XXtitleBar::XXtitleBar(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::XXtitleBar)
{
    ui->setupUi(this);
    setAttribute(Qt::WA_StyledBackground);
    setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);

    // arg init
    _willCloseBlock = nullptr;
    _logoSquared = false;
    _buttonSquared = false;
    _topPadding=_leftPadding=_bottomPadding=_rightPadding=0;

    // view init
    setWindow(this->window());
    ui->pushButton_r->setCheckable(true);
    QList<QPushButton*> buttons = {ui->pushButton_min,ui->pushButton_r,ui->pushButton_close};
    foreach(auto button, buttons){
        button->setFlat(true);
        connect(button,&QPushButton::clicked,this,&XXtitleBar::onWindowButtonClicked);
    }

    // run
    setDefaultStyleEnabled(true);
}
XXtitleBar::~XXtitleBar(){
    delete ui;
}

void XXtitleBar::setCloseBlock(std::function<bool(void)> willClose){
    _willCloseBlock = willClose;
}

void XXtitleBar::setTitle(QString title){
    ui->label_title->setText(title);
}
void XXtitleBar::setLogo(QIcon logo){
    if(logo.isNull()){
        ui->label_logo->hide();
        return;
    }
    ui->label_logo->setPixmap(logo.pixmap(logo.availableSizes().first()));
    ui->label_logo->setScaledContents(true);
}

void XXtitleBar::setPadding(int padding){
    _topPadding=_leftPadding=_bottomPadding=_rightPadding=padding;
}
void XXtitleBar::setPadding(int top, int left, int bottom, int right){
    _topPadding=top;
    _leftPadding=left;
    _bottomPadding=bottom;
    _rightPadding=right;
}

void XXtitleBar::setDefaultStyleEnabled(bool enable){
    setLogoSquared(enable);
    setLogoMargin(enable?4:0);
    setButtonSquared(enable);
    setButtonSystemIcon(enable);

    QString ss = !enable ? "" :
                           "QPushButton#pushButton_min,QPushButton#pushButton_r,QPushButton#pushButton_close{"
                           "    background:transparent;"
                           "}";
    setStyleSheet(ss);
}
void XXtitleBar::setLogoSquared(bool squared){
    if(_logoSquared==squared){
        return;
    }
    _logoSquared = squared;
    if(_logoSquared){
        int x = qMin(size().width(),size().height());
        ui->label_logo->setFixedSize(x,x);
    }
    else{
        ui->label_logo->setFixedSize(QWIDGETSIZE_MAX,QWIDGETSIZE_MAX);
    }
}
void XXtitleBar::setLogoMargin(int margin){
    ui->label_logo->setMargin(margin);
}
void XXtitleBar::setButtonSquared(bool squared){
    if(_buttonSquared==squared){
        return;
    }
    _buttonSquared = squared;

    QList<QPushButton*> buttons = {ui->pushButton_min,ui->pushButton_r,ui->pushButton_close};
    if(_buttonSquared){
        int x = qMin(size().width(),size().height());
        foreach(auto button, buttons){
            button->setFixedSize(x,x);
        }
    }
    else{
        foreach(auto button, buttons){
            button->setMinimumSize(0,0);
            button->setMaximumSize(QWIDGETSIZE_MAX,QWIDGETSIZE_MAX);
        }
    }
}
void XXtitleBar::setButtonSystemIcon(bool enable){
    if(enable){
        QIcon minIcon;
        minIcon.addPixmap(style()->standardPixmap(QStyle::SP_TitleBarMinButton),QIcon::Normal);
        ui->pushButton_min->setIcon(minIcon);

        QIcon closeIcon;
        closeIcon.addPixmap(style()->standardPixmap(QStyle::SP_TitleBarCloseButton),QIcon::Normal);
        ui->pushButton_close->setIcon(closeIcon);

        QIcon rIcon;
        rIcon.addPixmap(style()->standardPixmap(QStyle::SP_TitleBarNormalButton),QIcon::Normal,QIcon::Off);
        rIcon.addPixmap(style()->standardPixmap(QStyle::SP_TitleBarMaxButton),QIcon::Normal,QIcon::On);
        ui->pushButton_r->setIcon(rIcon);
    }
    else{
        ui->pushButton_min->setIcon(QIcon());
        ui->pushButton_r->setIcon(QIcon());
        ui->pushButton_close->setIcon(QIcon());
    }
}

void XXtitleBar::setWindowElementsHint(WindowElements es){
    ui->pushButton_min->setHidden(!(es&WindowElement::Min));
    ui->pushButton_r->setHidden(!(es&WindowElement::R));
    ui->pushButton_close->setHidden(!(es&WindowElement::Close));
    ui->label_logo->setHidden(!(es&WindowElement::Logo));
    ui->label_title->setHidden(!(es&WindowElement::Title));
}

void XXtitleBar::removeWidget(QString name){
    if(!_nameToWidget.contains(name)){
       return;
    }
    QSharedPointer<QWidget> widget = _nameToWidget.take(name);
    widget->deleteLater();
}

bool XXtitleBar::eventFilter(QObject *w, QEvent *e){
    Q_UNUSED(w);
    if(QEvent::WindowTitleChange == e->type()){
        QWidget *widget = qobject_cast<QWidget*>(w);
        if(widget){
            setTitle(widget->windowTitle());
        }
    }
    else if(QEvent::WindowIconChange == e->type()){
        QWidget *widget = qobject_cast<QWidget*>(w);
        if(widget){
            setLogo(widget->windowIcon());
        }
    }
    else if(QEvent::WindowStateChange == e->type()){
        QWidget *widget = qobject_cast<QWidget*>(w);
        if(widget){
            if(widget->windowState() == Qt::WindowState::WindowNoState){
                setMaxWindowState(false);
            }
            else if(widget->windowState() == Qt::WindowState::WindowMaximized){
                setMaxWindowState(true);
            }
            else{

            }
        }
    }
    else{

    }
    return QWidget::eventFilter(w,e);
}
void XXtitleBar::resizeEvent(QResizeEvent *event){
    QWidget::resizeEvent(event);
    int x = qMin(event->size().width(),event->size().height());
    if(_logoSquared && !ui->label_logo->isHidden()){
        ui->label_logo->setFixedSize(x,x);
        if(ui->label_logo->margin()>0){
            int xx = x/4;
            if(xx>0){
                ui->label_logo->setMargin(xx);
            }
        }
    }
    if(_buttonSquared){
        QList<QPushButton*> buttons={ui->pushButton_min,ui->pushButton_r,ui->pushButton_close};
        foreach(auto button, buttons){
            button->setFixedSize(x,x);
        }
    }
}
void XXtitleBar::mousePressEvent(QMouseEvent *event){
#ifdef Q_OS_WIN
    if (ReleaseCapture() && window()->isTopLevel() && isAvailableArea(event->pos())){
        SendMessage(HWND(window()->winId()), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
    }
    event->ignore();
#else
#endif
}
QSize XXtitleBar::sizeHint() const{
    return QSize(150,40);
}

bool XXtitleBar::isAvailableArea(QPoint point){
    QRect rect = QRect(_leftPadding,_topPadding,width()-_leftPadding-_rightPadding,height()-_topPadding-_bottomPadding);
    return rect.contains(point);
}
void XXtitleBar::setWindow(QWidget *window){
    if(window){
        setTitle(window->windowTitle());
        setLogo(window->windowIcon());
        window->installEventFilter(this);
    }
}
void XXtitleBar::setMaxWindowState(bool max){
    ui->pushButton_r->setChecked(max);
}
void XXtitleBar::addWidget(QString name, QSharedPointer<QWidget> widget, Position position){
    _nameToWidget.insert(name,widget);
    if(Left == position){
        ui->horizontalLayout_main->insertWidget(1,widget.data());
    }
    else if(Right == position){
        ui->horizontalLayout_main->insertWidget(ui->horizontalLayout_main->count()-1,widget.data());
    }
    else{

    }
}
void XXtitleBar::onWindowButtonClicked(bool checked){
    Q_UNUSED(checked);

    QAbstractButton * const button = qobject_cast<QAbstractButton*>(sender());
    if(nullptr == button){
        return;
    }
    if(button == ui->pushButton_min){
        this->window()->showMinimized();
    }
    else if(button == ui->pushButton_r){
        if(this->window()->isMaximized()){
            this->window()->showNormal();
        }
        else{
            this->window()->showMaximized();
        }
    }
    else if(button == ui->pushButton_close){
        if(nullptr != _willCloseBlock){
            bool accpet = _willCloseBlock();
            if(accpet){
                this->window()->close();
            }
        }
        else{
            this->window()->close();
        }
    }
    else{

    }
}
